Material Design系列教程(8) - TabLayout

简介

TabLayout:顾名思义,就是能够提供给我们标签页功能的控件。它通常用于与
ViewPager 联合使用,使界面具备滑动切换标签功能(TabLayout 本身已提供接口无缝结合 ViewPager 使用)。

来看下 TabLayout 的官方文档描述:

TabLayout

可以看到,TabLayout 存在于 design 包中,且继承于 HorizontalScrollView,提供了一个水平布局去显示标签页面。

TabLayout 的常用属性和方法

TabLayout 除了 Android 控件固有的属性(以 android: 为命名空间)之外,还定义了些特有的属性(是以 ”app:” 的命名空间的,形如app:tabMode),下面罗列一些使用相对频繁的属性:

属性 描述
app:tabMode 设置标签(tab)布局模式。有如下两种选项:

"fixed":默认值,表示标签页不能滚动。一般用于标签较少的情况,每个 Tab 可以平分屏幕宽度。

"scrollable":表示标签页可以滚动展示。使用于标签文本过长和过多标签页这些情况。该模式通常在结合 ViewPager 中使用。当使用该属性时,tabGravity的设置就不起作用了,标签都是从左向右布局。

对应代码方法:setTabMode(int)
app:tabGravity 设置标签页(tab)对齐方式。有如下两种选项:

"fill":所有标签页(tab)填满 TabLayout 宽度,该选项只有在app:tabMode="fixed"的时候才生效 。

"center":标签页居中显示。

对应代码方法:setTabGravity(int)
app:tabTextColor 未选中标签页时,字体的颜色
app:tabSelectedTextColor 选中标签页时,字体的颜色
app:tabIndicatorColor 滑动时,指示器的颜色
app:tabIndicatorHeight 设置指示器高度
app:tabBackground 标签页(tab)布局背景
app:tabTextAppearance 设置标签页标题文字样式
app:tabPadding 标签页内边距
app:tabContentStart 标签页(tab)左边距内容偏移量,该选项只有在app:tabMode="scrollable"时才生效
app:tabMaxWidth 标签页最大宽度
app:tabMinWidth= 标签页最小宽度

下面罗列 TabLayout 一些相对重要的方法:

方法 描述
newTab() 创建一个新的标签
addTab(Tab) 添加标签页
removeTab(Tab) 删除标签页
removeTabAt(int) 通过索引,删除标签页
removeAllTabs() 删除所有标签页
getTabCount() 返回标签页数量
getTabAt(int) 返回索引对应的标签 页
getSelectedTabPosition() 返回当前选中的标签页索引,若未选中,则返回 -1
addOnTabSelectedListener(OnTabSelectedListener) 添加监听器
removeOnTabSelectedListener(OnTabSelectedListener) 移除监听器
clearOnTabSelectedListeners() 清除所有的监听器
addView TabLayout 是一个ViewGroup,所以可以直接添加子View
setupWithViewPager(ViewPager) TabLayoutViewPager 关联,随着 ViewPager 滑动而切换标签。
TabLayoutViewPager 关联后,TabLayout 的标签页(tab)数量由 ViewPager 分页数量决定,TabLayout 的标签内容由 ViewPagerAdaptergetPagerTitle()方法返回的内容决定

示例

  • 直接为 TabLayout 添加标签(tab):
 TabLayout tabLayout = ...;
 tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
 tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));
 tabLayout.addTab(tabLayout.newTab().setText("Tab 3"));

可以看到:newTab 就是创建一个新的标签,然后通过 addTab 添加该标签到 TabLayout 中。

当然也可以直接在布局文件中指定标签,但是实际开发中一般不这样用:

<android.support.design.widget.TabLayout
         android:layout_height="wrap_content"
         android:layout_width="match_parent">

     <android.support.design.widget.TabItem
             android:text="@string/tab_text"/>

     <android.support.design.widget.TabItem
             android:icon="@drawable/ic_android"/>

 </android.support.design.widget.TabLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/tablayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

从上面的布局中,我们可以看出,布局很简单,就只包含 TabLayoutViewPager,且 TabLayout 的特有属性均使用默认值。

然后再来看下源码:

public class TabLayoutActivity extends AppCompatActivity {
    private static final int TAB_NUM = 3;

    @BindView(R.id.viewpager)
    private ViewPager mViewPager;
    @BindView(R.id.tablayout)
    private TabLayout mTabLayout;

    private List<Fragment> mFragments;

    @Override
    @ViewInject(ViewInject.ACTIVITY)
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab);
        initData();
        initView();
    }

    private void initData() {
        this.mFragments = new ArrayList<>();
    }

    private void initView() {
//        generate Fragmetns
        for (int i = 0; i < TabLayoutActivity.TAB_NUM; ++i) {
            this.mFragments.add(MyFragment.newInstance("Fragmetn: " + i));
        }
//        set up adapter for ViewPager
        this.mViewPager.setAdapter(new FragmentPagerAdapter(this.getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return TabLayoutActivity.this.mFragments.get(position);
            }

            @Override
            public int getCount() {
                return TabLayoutActivity.this.mFragments.size();
            }

            @Nullable
            @Override
            public CharSequence getPageTitle(int position) {
                return "Tab" + position;
            }
        });
//        connect TabLayout and ViewPager
        this.mTabLayout.setupWithViewPager(this.mViewPager);
    }
}

首先是创建3个Fragment,然后给 ViewPager 设置一个FragmentPagerAdapter,将先前创建的Fragment通过该Adapter设置给 ViewPager。最后通过setupWithViewPagerTabLayoutViewPager 关联起来。

上述代码的效果如下:

TabLayout default value

更多代码详情,请查看:TODO::

接下来,我们改变一下 TabLayoutapp:tabModeapp:tabGravity,来看下效果有什么不同:

  • app:tabMode="fixed"app:tabGravity="center",效果如下:
tabMode="fixed"`且`tabGravity="center"`

可以看到跟我们上面的示例是一摸一样的,也就是app:tabMode="fixed"app:tabGravity="center"就是默认的值。

  • app:tabMode="fixed"app:tabGravity="fill",效果如下:
tabMode="fixed"`且`tabGravity="fill"`

可以看到,因为app:tabMode="fixed"表示标签无法滚动,而app:tabGravity="fill"表示填满标签(tab),因此这里的效果就是标签页均分填满了 TabLayout

  • 前面我们说过,当app:tabMode="scrollable"时,tabGravity的设置就不起作用了,所以我们直接来看下app:tabMode="scrollable"的效果:
app:tabMode="scrollable"

可以看到,app:tabMode="scrollable"时,标签页布局默认都是从左往右排列的。

一般使用app:tabMode="scrollable"都是用于标签过多的情况的,此时,可以通过滑动标签来进行选择,效果如下所示:

app:tabMode="scrollable"

总结

  • app:tabMode="fixed"时,若app:tabGravity="center",则标签居中显示;若app:tabGravity="fill"时,则标签均分填满 TabLayout

  • app:tabMode="scrollable"时,app:tabGravity不起作用,默认标签布局为从左往右排列,该属性一般用于标签过多情况,可以通过直接滑动标签进行选取。

最后,如果我们想把标签放置到布局底部,应该怎样做呢?

其实很简单,只需更改布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" />  //占用上面,留出位置给TabLayout

    <android.support.design.widget.TabLayout
        android:id="@+id/tablayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        app:tabGravity="fill"
        app:tabIndicatorHeight="0dp" //因为默认指示器在下面,不合适使用在底部菜单所以直接设置其高度为0
        app:tabMode="fixed"
        app:tabSelectedTextColor="#FFFFFF"
        app:tabTextColor="#000000" />
</LinearLayout>

效果如下:

TabLayout_bottom

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容